#ifndef __PERCPU_DEFS_H__
#define __PERCPU_DEFS_H__   

#include "linux/types.h"
#include "linux/init.h"
#include "asm-generic/percpu.h"
#include "linux/compiler.h"
#include "linux/cache.h"

#define PER_CPU_SHARED_ALIGNED_SECTION ""
#define PER_CPU_ALIGNED_SECTION "..shared_aligned"
#define PER_CPU_FIRST_SECTION ""

#ifdef CONFIG_SMP
#define PER_CPU_BASE_SECTION ".data..percpu"
#else
#define PER_CPU_BASE_SECTION ".data"
#endif

#define PER_CPU_ATTRIBUTES
#define PER_CPU_DEF_ATTRIBUTES

#define __PCPU_ATTRS(sec) 	__percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))	PER_CPU_ATTRIBUTES

#define DECLARE_PER_CPU_SECTION(type, name, sec) extern __PCPU_ATTRS(sec) __typeof__(type) name
#define DEFINE_PER_CPU_SECTION(type, name, sec)	__PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES __typeof__(type) name

#define DECLARE_PER_CPU(type, name)  DECLARE_PER_CPU_SECTION(type, name, "")
#define DEFINE_PER_CPU(type, name) DEFINE_PER_CPU_SECTION(type, name, "")

#define DECLARE_PER_CPU_SHARED_ALIGNED(type, name)  	DECLARE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) ____cacheline_aligned_in_smp
#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)		DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) 	____cacheline_aligned_in_smp

#define __verify_pcpu_ptr(ptr)                                       \
    do                                                               \
    {                                                                \
        const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \
        (void)__vpp_verify;                                          \
    } while (0)

#define VERIFY_PERCPU_PTR(__p)                    \
    ({                                            \
        __verify_pcpu_ptr(__p);                   \
        (typeof(*(__p)) __kernel __force *)(__p); \
    })

#define SHIFT_PERCPU_PTR(__p, __offset)					\
	RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset))

#define per_cpu_ptr(ptr, cpu)						\
({									\
	__verify_pcpu_ptr(ptr);						\
	SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu)));			\
})


#define per_cpu(var, cpu)	(*per_cpu_ptr(&(var), cpu))

#endif